﻿/**
* @private
* @license	GNU GPLv2
*
* Copyright (C) 2007  Polly Jex.
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
* MA  02110-1301, USA.
*
* @see	http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*/

package com.kirika.data.tda {

	/**
	 * @import
	 */
	
	import com.kirika.core.CoreObject;
	import com.kirika.data.ICollection;
	import com.kirika.data.IIterator;
	import com.kirika.utils.TypeUtil;
	
	/**
	 * Modelo abstracto de Coleccion.
	 * @author	Polly Jex (pollyjex@emc2zen.com.ar)
	 */
	public class AbstractCollection extends CoreObject implements ICollection {
		
		/**
		 * Registro de coleccion.
		 */
		private var _record:Array;
		
		/**
		 * Constructor.
		 * @param	value	Estructura de datos.
		 * @return	AbstractCollection
		 */
		public function AbstractCollection( value:Array = null ) {
			
			if( ! TypeUtil.isNull( value ) ){				
				this._record = value.slice();				
			}else{				
				clear();				
			}
			
		}
		
		/**
		 * Inserta un nuevo elemento a la coleccion.
		 * @param	value	Elemento a insertar.
		 * @return	Boolean
		 */
		public function add( value:* ):Boolean {
			
			return this.ResolveAdd( value );
			
		}
		
		/**
		 * Inserta una coleccion de datos a la coleccion.
		 * @param	value	Elemento a insertar.
		 * @return	Boolean
		 */
		public function addAll( value:ICollection ):Boolean {
			
			return this.ResolveAdd( value );
			
		}
		
		/**
		 * Reinicia la coleccion de datos.
		 * @return	void
		 */
		public function clear():void {
			
			this._record = new Array();
			
		}
		
		/**
		 * Retorna <code>true</code> si la coleccion contiene el elemento especifico, en caso contrario retorna <code>false</code>.
		 * @param	value	Elemento a verificar.
		 * @return	Boolean
		 */
		public function contains( value:* ):Boolean {
			
			return this.ResolveContains( value );
			
		}
		
		/**
		 * Retorna <code>true</code> si la coleccion contiene los valor de la coleccion de datos especifica, en caso contrario retorna <code>false</code>.
		 * @param	value	Elementos a verificar.
		 * @return	Boolean
		 */
		public function containsAll( value:ICollection ):Boolean {
			
			return this.ResolveContains( value );
			
		}
		
		/**
		 * Retorna <code>true</code> si la coleccion es igual a la coleccion de datos especifica, en caso contrario retorna <code>false</code>.
		 * @param	value	Valor a verficar.
		 * @return	Boolean
		 */
		public function equals( value:* ):Boolean {
			
			return new Boolean( value === this );
			
		}
		
		/**
		 * Retorna <code>true</code> si la coleccion no contiene ningun elemento, en caso contrario retorna <code>false</code>.
		 * @return	Boolean
		 */
		public function isEmpty():Boolean {
			
			return new Boolean( this.size() < 1 );
			
		}
		
		/**
		 * Retorna un iterador con los elementos de la coleccion.
		 * @return	IIterator
		 */
		public function iterator():IIterator {
			
			return new AbstractIterator( this.toArray() );
			
		}
		
		/**
		 * Remueve el valor de la coleccion.
		 * @param	value	Elemento a remover.
		 * @return	Boolean
		 */
		public function remove( value:* ):Boolean {			
			
			return this.ResolveRemove( value );
			
		}
		
		/**
		 * Remueve todos lo eslementos de la coleccion que contiene la coleccion definida.
		 * @param	value	Elementos a remover.
		 * @return	Boolean
		 */
		public function removeAll( value:ICollection ):Boolean {
			
			return this.ResolveRemove( value );
			
		}
		
		/**
		 * Retiene solo los elementos de la coleccion que contine la coleccion definida.
		 * @param	value	Elementos a retener.
		 * @return	Boolean
		 */
		public function retainAll( value:ICollection ):Boolean {
			
			return this.ResolveRetain( value );
			
		}
		
		/**
		 * Busca y retorna la posicion del elemento en la coleccion, retorna <code>-1</code> si el elemento no existe.
		 * @param	value 	Elemento a buscar.
		 * @return	int
		 */
		public function search( value:* ):int {
			
			return this._record.indexOf( value );
			
		}
		
		/**
		 * Retorna el numero de elementos en la coleccion.
		 * @return	uint
		 */
		public function size():uint {
			
			return this._record.length;
			
		}
		
		/**
		 * Retorna el contenido de la coleccion en un Array, siendo el mismo una copia.
		 * @return	Array
		 */
		public function toArray():Array {
			
			return this._record.slice();
			
		}
		
		/**
		 * Retorna el contenido de la coleccion en un Array.
		 * @return	Array
		 */
		protected function toSource():Array {
			
			return this._record;
			
		}
		
		/**
		 * Resuelve la insercion de uno o mas elementos a la coleccion.
		 * @param	value	Elemento/s a insertar.
		 * @return	Boolean
		 */
		protected function ResolveAdd( value:* ):Boolean {
			
			var oldSize:uint = this.size();
			
			if( ! TypeUtil.thisIs( value, ICollection ) ){				
				this._record.push( value );				
			}else{				
				this._record = this._record.concat( value.toArray() );		
			}
			
			return new Boolean( this.size() > oldSize );
			
		}
		
		/**
		 * Resuelve la busqueda de uno o mas elementos en la coleccion.
		 * @param	value	Elemento/s a insertar.
		 * @return	Boolean
		 */
		protected function ResolveContains( value:* ):Boolean {
			
			var i:IIterator = this.ResolveArgument( value );
			
			while( i.hasNext() ){				
				if( this.search( i.next() ) == -1 ){
					return false;
				}				
			}
			
			return true;
			
		}
		
		/**
		 * Resuelve la remocion de uno o mas elementos de la coleccion.
		 * @param	value	Elemento/s a remover.
		 * @return	Boolean
		 */
		protected function ResolveRemove( value:* ):Boolean {			
			
			var position:int;
			var oldSize:uint = this.size();
			var oldRecord:Array = this.toArray();
			var i:IIterator = this.ResolveArgument( value );
			
			while( i.hasNext() ){
				
				position = this.search( i.next() );
				
				if( position > -1 ){
					this._record.splice( position, 1 );
				}
				
			}
			
			if( i.size() > 1 ){
				
				if( this.size() != ( oldSize - i.size() ) ){
					this._record = oldRecord;
					return false;
				}else{					
					return true;
				}
				
			}else{
				
				return new Boolean( this.size() < oldSize );
				
			}			
			
		}
		
		/**
		 * Resuelve la retencion de uno o mas elementos de la coleccion.
		 * @param	value	Elemento/s a retener.
		 * @return	Boolean
		 */
		protected function ResolveRetain( value:ICollection ):Boolean {
			
			if( this.containsAll( value ) ){
				this._record = value.toArray();
				return true;
			}
			
			return false;
			
		}
		
		/**
		 * Resuelve el argumento y retorna una instacia de <code>IIterator</code>.
		 * @param	value	Elemento a procesar.
		 * @return	IIterator
		 */
		protected function ResolveArgument( value:* ):IIterator {
			
			if( ! TypeUtil.thisIs( value, ICollection ) ){
				return new AbstractIterator( [ value ] );
			}else{
				return value.iterator();
			}
			
		}
		
	}
	
}
